#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <omp.h>
#include <sys/timeb.h>
#include "preprocessor.h"

// Funcao que pega o tempo 
long getmillis() {
    struct timeb mtimebuffer;

    ftime(&mtimebuffer);
    return 1000 * mtimebuffer.time + mtimebuffer.millitm;
}

int main(int argc, char * args[]) {


    //     Variaveis auxiliares utilizada por todo o programa
    int i;
    int j;

    //     Variavel que contem o numero total de palavras
    int counter_wordTotal = 0;
    //     Variavel que contem o numero encontrado de palavras
    int counter_wordParcial = 0;
    //     Variavel que contem o tamanho de uma determinada palavra
    int words_size[46] = {0};


    FILE *pFile;

    /* Arvores primarias */
    /* Arvore primaria que contem as palavras completas */
    node *words = NULL;
    node *words5 = NULL;
    node *words10 = NULL;
    node *words15 = NULL;
    node *words20 = NULL;
    node *words25 = NULL;

    /* Arvores secundarias */
    /* Arvore secundaria que contem as palavras encontradas completas */
    node *words2_5 = NULL;
    node *words2_10 = NULL;
    node *words2_15 = NULL;
    node *words2_20 = NULL;
    node *words2_25 = NULL;


    //     Variaveis para calcular o tempo
    long mtimea;
    long mtimeb;

    //     Pre-processador do texto
    words = preProcessor(&counter_wordTotal, words_size, &words5, &words10, &words15, &words20, &words25);


    pFile = fopen("res_word_3.txt", "w");
    //     Variaveis auxiliares do algoritmo de aleatoriedade
    int n;
    int w;
    char c;
    //     Variavel que recebe o ID da thread
    int th_id;
    //     Flag que verifica se teve varias palavras nao encontradas e troca de alfabeto
    int flag = 0;
    //     Contadores gerais de porcentagem e tempo do programa
    double porcent = 0.0;
    int porcent_int = 0;
    int words_left = 0;
    mtimeb = getmillis();

    //  Inicio do bloco paralelo
#pragma omp parallel private(th_id,i,j)
    {
        //      Nós auxiliares
        node* aux;
        node* aux_tree;
        //         Alfabeto utilizado
        char chars[27] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
            'x', 'y', 'z', '{'};
        int r;
        th_id = omp_get_thread_num();

        srand(time(NULL) * th_id);
        // Inicio da geração aleatoria de palavras
        while (1) {
            char s[50] = {0};

            if (flag > 10000) {
                srand(time(NULL) * th_id);
                flag = 0;
                r = rand() % 27;

                for (w = 0; w < 27; w++)
                    chars[w] = ((chars[w] - 'a') + r) % 27 + 'a';

            }
            /* loop que limita o tamanho da palavra a ser criada */
            for (i = 1; i <= 100; i++) {
                flag++;
                /* gera a palavra de tamanho i */
                for (j = 1; j <= i; j++) {
                    /* gera-se a palavra aleatoria */
                    n = rand() % 27;
                    c = chars[n];
                    s[j - 1] = c;
                    // Verifica-se a palavra foi bem formada
                    if (findN(s, words, j) == NULL)
                        j = i;

                    /*
                     * Todos os blocos de if abaixo seguem a mesma ideia
                     * portanto comentaremos o funcionamento do primeiro, que eh
                     * equivalente para todos os outros nessa funcao
                     */
                    /* se encontrou a palavra na arvore de 0 a 5 letras  */
                    aux = find(s, words5);
                    if (aux != NULL) {
                        /* procura-se pela mesma na arvore secundaria de 0 a 5 letras */
                        if (find(s, words2_5) == NULL) {

                            /* reset a variavel de rotacao do alfabeto */
                            flag = 0;
                            /* insere-se a palavra na arvore secundaria */
                            words2_5 = insert(s, words2_5);

                            while (aux->rowSub != NULL) {
                                aux_tree = findSub(getRowNode(aux), words, 0);
                                if (aux_tree->complete) {
                                    fprintf(pFile, "%s\n", aux_tree->word);
                                    /* incrementa a quantidade de palavras encontradas */
                                    counter_wordParcial++;
                                }

                            }
                            // Calculo de tempo e palavras encontradas
                            if (words_left != counter_wordTotal - counter_wordParcial) {
                                if (porcent_int % 10 == 0 || porcent >= 99.0) {
                                    mtimea = getmillis();
                                    words_left = counter_wordTotal - counter_wordParcial;
                                    printf("Tempo de %f eh = %d, faltam %d palavras\n", porcent, mtimea - mtimeb, words_left);
                                }

                                porcent = (counter_wordParcial * 100.0) / counter_wordTotal;
                                porcent_int = (int) porcent;
                            }

                        }
                    }

                    /* o mesmo que o anterior para a arvore de 5 a 10 letras */
                    aux = find(s, words10);
                    if (aux != NULL) {
                        if (find(s, words2_10) == NULL) {

                            flag = 0;
                            words2_10 = insert(s, words2_10);
                            while (aux->rowSub) {
                                aux_tree = findSub(getRowNode(aux), words, 1);
                                if (aux_tree->complete) {
                                    fprintf(pFile, "%s\n", aux_tree->word);

                                    counter_wordParcial++;
                                }

                            }
                            if (words_left != counter_wordTotal - counter_wordParcial) {
                                if (porcent_int % 10 == 0 || porcent >= 99.0) {
                                    mtimea = getmillis();
                                    words_left = counter_wordTotal - counter_wordParcial;
                                    printf("Tempo de %f eh = %d, faltam %d palavras\n", porcent, mtimea - mtimeb, words_left);
                                }

                                porcent = (counter_wordParcial * 100.0) / counter_wordTotal;
                                porcent_int = (int) porcent;
                            }

                        }
                    }

                    /* o mesmo que o anterior para a arvore de 10 a 15 letras */
                    aux = find(s, words15);
                    if (aux != NULL) {
                        if (find(s, words2_15) == NULL) {

                            flag = 0;
                            words2_15 = insert(s, words2_15);
                            while (aux->rowSub) {
                                aux_tree = findSub(getRowNode(aux), words, 2);
                                if (aux_tree->complete) {
                                    fprintf(pFile, "%s\n", aux_tree->word);
                                    counter_wordParcial++;
                                }

                            }

                            if (words_left != counter_wordTotal - counter_wordParcial) {
                                if (porcent_int % 10 == 0 || porcent >= 99.0) {
                                    mtimea = getmillis();
                                    words_left = counter_wordTotal - counter_wordParcial;
                                    printf("Tempo de %f eh = %d, faltam %d palavras\n", porcent, mtimea - mtimeb, words_left);
                                }

                                porcent = (counter_wordParcial * 100.0) / counter_wordTotal;
                                porcent_int = (int) porcent;
                            }

                        }
                    }
                    /* o mesmo que o anterior para a arvore de 15 a 20 letras */
                    aux = find(s, words20);
                    if (aux != NULL) {
                        if (find(s, words2_20) == NULL) {

                            flag = 0;
                            words2_20 = insert(s, words2_20);

                            while (aux->rowSub) {
                                aux_tree = findSub(getRowNode(aux), words, 3);

                                if (aux_tree->complete) {
                                    fprintf(pFile, "%s\n", aux_tree->word);
                                    counter_wordParcial++;
                                }

                            }

                            if (words_left != counter_wordTotal - counter_wordParcial) {
                                if (porcent_int % 10 == 0 || porcent >= 99.0) {
                                    mtimea = getmillis();
                                    words_left = counter_wordTotal - counter_wordParcial;
                                    printf("Tempo de %f eh = %d, faltam %d palavras\n", porcent, mtimea - mtimeb, words_left);
                                }

                                porcent = (counter_wordParcial * 100.0) / counter_wordTotal;
                                porcent_int = (int) porcent;

                            }
                        }
                    }

                    /* o mesmo que o anterior para a arvore de 20 ou mais letras */
                    aux = find(s, words25);
                    if (aux != NULL) {
                        if (find(s, words2_25) == NULL) {

                            flag = 0;
                            words2_25 = insert(s, words2_25);

                            while (aux->rowSub) {
                                aux_tree = findSub(getRowNode(aux), words, aux->blocks);

                                if (aux_tree->complete) {
                                    fprintf(pFile, "%s\n", aux_tree->word);
                                    counter_wordParcial++;
                                }

                            }

                            if (words_left != counter_wordTotal - counter_wordParcial) {
                                if (porcent_int % 10 == 0 || porcent >= 99.0) {
                                    mtimea = getmillis();
                                    words_left = counter_wordTotal - counter_wordParcial;
                                    printf("Tempo de %f eh = %d, faltam %d palavras\n", porcent, mtimea - mtimeb, words_left);
                                }

                                porcent = (counter_wordParcial * 100.0) / counter_wordTotal;
                                porcent_int = (int) porcent;

                            }
                        }
                    }
                    // Se o numero de palavras encontradas for o mesmo que o total então termina o programa
                    if (counter_wordParcial == (counter_wordTotal))
                        exit(0);
                }
            }
        }
    }


    fclose(pFile);








    return 0;
}


